package org.NooLab.glue.filter;

import java.util.Vector;

import org.NooLab.glue.MessageBoard;
import org.NooLab.glue.components.BoardInterpreterMessage;
import org.NooLab.glue.components.Message;
import org.NooLab.glue.components.MessageBoardConnector;
import org.NooLab.glue.components.SenderWrap;
import org.NooLab.glue.msgframe.BXMessage;
import org.NooLab.glue.msgframe.BasicMessageParams;
import org.NooLab.glue.msgframe.XMessage;
import org.NooLab.glue.msgframe.XRegistration;
import org.NooLab.glue.net.BoardAddress;
import org.NooLab.glue.net.RemoteAddress;
import org.NooLab.glue.subscription.FilterPackages;
import org.NooLab.glue.transaction.Transaction;
import org.NooLab.utilities.logging.PrintLog;
import org.NooLab.utilities.net.GUID;

public class BoardMessageInterpreter extends MessageInterpreter{

	SubscriptionHandlerInterpreter subscriptionHandler ;
	MessageBoardConnector mbc=null;
	
	 
	public BoardMessageInterpreter( MessageBoard messageboard, 
			 						FilterPackages filters, 
			 						PrintLog outprn){
		super( messageboard, filters, outprn );
		
		subscriptionHandler = new SubscriptionHandlerInterpreter( messageboard, filters, outprn);
		
	}
	
	 
	
	public int interpretingSingleBoardMessage( Message msg, MessageBoardConnector mbc){
		
		this.mbc = mbc;
		
		int result= -1;
		String rawXmlMsg,role ;
		int p1;
		String[] rawIndicators ;
		BXMessage xmsg ;
		 
		boolean isTransaction=false;
		
		rawXmlMsg = msg.rawXmlMsg ;
		
		// the classed thread ("SourceHandler") will take it in FiFo style and 
		// route it one by one to interpreteSourceMsg)=
		
		xmsg = new BXMessage(out) ;
		
		role = xmsg.getSpecifiedInfo(rawXmlMsg, "//messageboard", "role").toLowerCase();
		
		if ((rawXmlMsg.length()>40) && (role.contentEquals("iboard"))){
			
out.printErr(4,"\r\nIBOARD message received : \r\n"+rawXmlMsg);

			originatorID = xmsg.getInfoFromProlog( rawXmlMsg, "origin", "id", ".");
			rawXmlMsg = xmsg.removePrologFromXml(rawXmlMsg) ;
			
			if (originatorID.length()==0){
				originatorID = xmsg.getSpecifiedInfo(rawXmlMsg, "//originator", "id") ;
			}

			
			p1 = rawXmlMsg.indexOf("<transaction>");
			if (p1>0){
			
				xmsg.setContentRoot("transaction");
				
				// request for relay, sent to remote
				rawIndicators = new String[]{"<origin id=\"", "<request ", "<instance", "type=\"relay"} ;
				if (boardVariant_openRelayRelationResponse( xmsg, rawXmlMsg ,rawIndicators) ){ return result; }
				
				// receiving answer from remote, as created by "createRelayRequestResponse()" (see line 203, where it is used
				rawIndicators = new String[]{"secret=", "<instance", "<confirmation", "type=\"relay"} ;
				if (boardVariant_handlingRelayRequestResponse( xmsg, rawXmlMsg ,rawIndicators) ){ return result; }
				
				rawIndicators = new String[]{"a", "b" } ;
				if (boardVariant_acceptRelayedTransaction( xmsg, rawXmlMsg ,rawIndicators) ){ return result; }
				
			}
			
			p1 = rawXmlMsg.indexOf("<connect");
			if (p1>0){

				rawIndicators = new String[]{"<connect>","<instance","<origin","environment"} ;
				if (handlingConnectPingReply( xmsg, rawXmlMsg ,rawIndicators) ){ return result; }

				rawIndicators = new String[]{"<connect","<instance",} ;
				if (handlingConnectPing( xmsg, rawXmlMsg ,rawIndicators) ){ return result; }
 
			}
		
			p1 = rawXmlMsg.indexOf("<control>"); 
			if (p1>0){
				result= 0;
				 
				
				result = -3;;
			} // a control task message from other boards
			
			
		}
		
		return 0;
	}
	
	
	public boolean  boardVariant_acceptRelayedTransaction(BXMessage xmsg, String rawXmlMsg, String[] rawIndicators ) {
		Transaction relayTransaction ;
		
		// in transactions, search for the transaction using the secret and of type <TD_RELAY>
		
		boolean result=false;
		
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
		
		if ( result ){
		
			
			
			
		}
		
		return false;
	}
	
	/**
	 * on the side of the remote board, which will accept the relayed task
	 * we provide a transaction ID 
	 * 
	 * @param xmsg
	 * @param rawXmlMsg
	 * @param rawIndicators
	 * @return
	 */
	public boolean  boardVariant_openRelayRelationResponse(BXMessage xmsg, String rawXmlMsg, String[] rawIndicators ) {
		
		boolean result=false;
		String str, xmlOutStr , requestedDocType, requestInstanceName, secret;
		int availability=-1;
		long tid=0, transactionID, relayedtid;
		BasicMessageParams basics ;
		Transaction relayTransaction ;
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
		
		if ( result ){
			basics = new BasicMessageParams() ;
												out.print(2, "boardVariant_openRelayRelationResponse(), received raw message");
												out.print(2, rawXmlMsg+"\n-------------------------");
			str = "";
			
			
			// check the registered receptors for the requested doctype
			requestedDocType = xmsg.getSpecifiedInfo(rawXmlMsg, "request", "doctype");
			
			requestInstanceName = xmsg.getSpecifiedInfo(rawXmlMsg, "request", "secret");
			
			secret = xmsg.getSpecifiedInfo(rawXmlMsg, "instance", "name");
			
			// the transaction id  of the transaction (on the requesting MessageBoard)
			// that is asked to relay
			relayedtid = xmsg.getSpecifiedValue(rawXmlMsg, "origin", "id") ;
			
			// TODO: get a transaction ID from the LOCAL board!! 
			globalReceipts.incGlobalReceiptID(); ;
			transactionID = globalReceipts.getGlobalReceiptID(); 
			
			relayTransaction = new Transaction();
			relayTransaction.setTransactionID(transactionID) ;
			// relayTransaction.setContentType();
			
			secret = GUID.randomvalue();
			relayTransaction.setClientSecret( secret ) ;
			relayTransaction.setType( Transaction.TD_RELAY );
			
			mbf.getTransactions().addItem( relayTransaction );
			// in "boardVariant_acceptRelayedTransaction()" we will refer to this
			
			// should we use separate transaction types ?? 
			// Transactions relayTransactions; as part of the MessageBoard
			
			
			// include instance name, secret for identification on the other side
			
			// if ok then set the state of the respective receptor to "busy"
			// but remember it by means of the secret (will appear in task sending again!) 
			
					// contains a transaction secret, even for overlapping transactionIDs the transaction can
					// be identified
					basics.privateTransactionIdentifier = secret ; 
					basics.roleOfSender = "IBOARD";
					basics.instanceName = requestInstanceName;
					basics.transactionID = relayedtid ; // transactionID;
					
							
			// get all receptors
			availability = messageBoard.getReceptorCount( XRegistration.RST_IS_CNXCONF, XRegistration.RST_IS_AVAIL, requestedDocType, 1);
			
			
			xmlOutStr = xmsg.createRelayRequestResponse(basics, transactionID, requestedDocType, availability) ;
			
			// don't forget the originator !
			xmlOutStr = xmsg.insertRawToXml( originatorID, "originator","id", xmlOutStr, "</messageboard>",1);

			// return within session
															out.print(4,"returning message to requesting board : ");
															out.print(4, xmlOutStr+"\n..................................");
			SenderWrap sender = new SenderWrap(comBox);
			int r = sender.sendingMessage(xmlOutStr, -1);
			sender=null;
		}
		
		return result;
	}
	
	
	/**
	 * 
	 * we received a transaction id for the relay operation and a secret
	 * now we can send the transaction package to the other board
	 * 
	 * @param xmsg
	 * @param rawXmlMsg
	 * @param rawIndicators
	 * @return
	 */
	private boolean boardVariant_handlingRelayRequestResponse(BXMessage xmsg, String rawXmlMsg, String[] rawIndicators ) {
		
		boolean result=false;
		String str, xmlOutStr;
		BasicMessageParams basics ;
		BoardInterpreterMessage ibordMsg = new BoardInterpreterMessage();
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
		
		if ( result ){
												out.printErr(2, "\nboardVariant_handlingRelayRequestResponse(), received raw message");
												out.print(2, rawXmlMsg+"\n-------------------------");
			str = "";

			basics = new BasicMessageParams() ;

			
			ibordMsg.action = "performRelay" ;
			ibordMsg.transactionID = 1111;
			ibordMsg.transactionSecret = "abcdef-123456" ;
			
			ibordMsg.rawXmlMsg = rawXmlMsg;
			
			
			if (mbc!=null){
				mbc.getIboardMessages().add(ibordMsg) ;
			}
			// setting some state variable,  
			/*
			SenderWrap sender = new SenderWrap(comBox);
			sender.sendingMessage(xmlOutStr, -1);
			*/
		}
		
		return result;
	}	
	/**
	 * 
	 * this is called by the board looking for a remote board
	 * 
	 * 
	 * @param xmsg
	 * @param rawXmlMsg
	 * @param rawIndicators
	 * @return
	 */
	@SuppressWarnings("unused")
	public boolean handlingConnectPingReply(BXMessage xmsg, String rawXmlMsg, String[] rawIndicators ) {
		/*  0. the pinging gets initiated physically by MessageBoardFactory.BoardLinkConnector.checkForBoards()
		    
			1. before we send (in MessageBoardConnector.
				<messageboard name="spela" role="IBOARD">
				<connect action="ping">
      				<instance name="mb1-embeddedsrc-iboard-1-bedcd4b1-80a7-4c70-8dc3-a3fe3816b56f"/>
   				</connect>
   			   which is handled by handlingConnectPing() (see below)	
   			   
   			2. and we get returned

				<messageboard name="spela" role="IBOARD">
   					<connect>
      					<instance name="mb1-board-67cad94c-146b-4b63-b67c-19e3acdbaa60"/>
      					<origin value="mb1-embeddedsrc-iboard-1-bedcd4b1-80a7-4c70-8dc3-a3fe3816b56f"/>
      					<environment capacity="0"/>
   					</connect>
        */
		boolean result=false;	
		int port,nr,baix;
		String xmlout, name, responsiveAddr,secretOrigin,remoteBoardName;
		BasicMessageParams basics = new BasicMessageParams(); 
		XRegistration xreg;
		Vector<XRegistration> registeredInstances ;
		Vector<RemoteAddress>  addresses ;
		BoardAddress boardAddr;
		
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
		
		if ( result ){
		
			addresses = mbf.getFactoryProperties().getRemoteAddresses();
			
			registeredInstances	= messageBoard.getRegisteredInstances() ;
			
												out.print(4,"handlingConnectPing Reply (RR)");
		    responsiveAddr = xmsg.getSpecifiedInfo(rawXmlMsg, "//connect/responsiveaddress", "value") ;	  
		    
		    // that's us:
		    secretOrigin = xmsg.getSpecifiedInfo(rawXmlMsg, "//connect/origin", "value") ;	
		    
		    // that's the name of the remote board
		    remoteBoardName = xmsg.getSpecifiedInfo(rawXmlMsg, "//connect/instance", "name") ;
		    									out.print(4, "handlingConnectPing, instance is embedded source client \n"+
		    												 "       its name : "+ secretOrigin+"\n" +
		    												 "       responsive address is : "+responsiveAddr+"\n"+
		    												 "       name of remote board  : "+remoteBoardName );
		    // now we can complete the map which links the ip-address and a name
		    // ONLY this makes the remote board fully available!
		    
		    baix = boardAddresses.indexOf(responsiveAddr);
		    
		    if (baix>=0){
		    	boardAddr = boardAddresses.get(baix) ;
		    	if (boardAddr!=null){
		    		boardAddr.setState( BoardAddress.__BA_KNOWNMAP ) ;
		    		// such remote MessageBoards we can use !
		    	}
		    }
		}
	
		return result;
	}
	
	
	/**
	 * 
	 * this is called on the side of the remote ping
	 * refreshing the timer of last contact time for xRegistration, <br/>
	 * note, that for MessageBoards we apply only by name not by iid !
	 * 
	 * This will be called only for http-rest ! 
	 * 
	 * @param xmsg
	 * @param rawXmlMsg
	 * @param rawIndicators
	 * @return
	 */
	private boolean handlingConnectPing( BXMessage xmsg, String rawXmlMsg, String[] rawIndicators ) {
		
		boolean result=false;	
		int port,nr, mutualrelay, baix;
		String xmlout, name, targetedAddr;
		BasicMessageParams basics = new BasicMessageParams(); 
		XRegistration xreg;
		Vector<XRegistration> registeredInstances ;
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
		
		if ( result ){
												out.print(4,"handlingConnectPing (R)");
												out.print(5,"   "+rawXmlMsg);

            registeredInstances	= messageBoard.getRegisteredInstances() ;
			name = xmsg.getSpecifiedInfo(rawXmlMsg, "//connect/instance", "name") ;				
			
			
			targetedAddr = xmsg.getSpecifiedInfo(rawXmlMsg, "//connect/targetaddress", "value") ;	 
			
			mutualrelay = (int) xmsg.getSpecifiedValue(rawXmlMsg, "//connect/parameters", "mutualrelay") ;
			
			
			if (mutualrelay<=0){
				baix = boardAddresses.indexOf(targetedAddr);
			    
			    if (baix>=0){
			    	BoardAddress boardAddr = boardAddresses.get(baix) ;
			    	if (boardAddr!=null){
			    		boardAddr.setState( BoardAddress.__BA_DEACTIVED ) ;
			    	}
			    }
			}
					
			xreg = XRegistration.getItemByName(name, registeredInstances) ;

			
			if (xreg!=null){
				xreg.setInstanceTested(true);
				xreg.setLastCheckTime( System.currentTimeMillis()) ;
			}
			
			basics.instanceName = messageBoard.getMxReg().getNameOfApplicant() ;
			basics.roleOfSender = "IBOARD";
			basics.hostaddress = "" ;
			basics.privateTransactionIdentifier = name ;
			// basics.instanceName = messageBoard.getMBid();
			
			// number of avail receptors ?
			nr = messageBoard.getReceptorCount(0,0) ; // 0=lowest non error state value , 0=at laest
			
			xmlout = xmsg.createPingResponse( basics ,nr, targetedAddr);
			
			xmlout = xmsg.insertRawToXml( originatorID, "originator","id", xmlout, "</messageboard>",1);
			
			SenderWrap sender = new SenderWrap(comBox);
			int r = sender.sendingMessage(xmlout, xreg) ;
			sender=null;
		}
		return result;
	}
	
	
	
	@SuppressWarnings("unused")
	private boolean templateInterpreter( XMessage xmsg, String rawXmlMsg, String[] rawIndicators ){ 
		boolean result=false ;
		long transactionID, iid ;
		
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
		
		if ( result ){
			result = false;
			
			
			
		}
		
		return result;
	}
}
